// pargma once
#include<iostream>
#include<fstream>
#include<sstream>
#include<unordered_map>
#include "Socket.hpp"
#include <vector>
const std::string wwwroot = "./wwwroot"; // web根目录
const std::string HomePage = "index.html";
const std::string protocol_sep = "\r\n";

class TcpServer;
struct ThreadData
{
    int fd_;
    TcpServer*ts;
};

class Request
{
public:
    Request()
    {
    }
    bool Deserialize(std::string rq) // 反序列化
    {
        while (true)
        {
            size_t pos = rq.find(protocol_sep);
            if (pos == std::string::npos)
                return false;
            std::string line = rq.substr(0, pos);
                rq.erase(0, pos+protocol_sep.size());

            if (!line.empty())
            {
                request_header.push_back(line);
            }
            else
            break;
        }
        text_=rq;
        return true;
    }
    void Parsing()
    {
        std::stringstream ss(request_header[0]);
        ss>>method_>>url_>>httpversion_;
        file_path=wwwroot;
        //判断url： /或/index.html ->wwwroot/index.html   /a/b/c/d/xxx.html -> wwwroot/a/b/c/d/xxx.html
        if(url_=="/"||url_=="/index.html")
        {
            file_path+="/";
            file_path+=HomePage;
        }
        else
        file_path+=url_;
       size_t pos =file_path.rfind(".");
       if(pos==std::string::npos)
       {
        suffix_=".html";
       }
       else
       {
        suffix_=file_path.substr(pos);
       }
    }
    void DebugPrint()
    {
        for(auto &line:request_header)
        {
            std::cout<<line<<std::endl;
        }
    
    }
    ~Request()
    {
    }

private:
    std::vector<std::string> request_header; // 把正文前的内容一个个分隔到vector内
    std::string text_;                       // 请求正文

    //解析之后的结果
    std::string method_;
    std::string url_;
    std::string httpversion_;
    public:
    std::string file_path;
    std::string suffix_;//后缀
};
class TcpServer
{
public:
    TcpServer(const uint16_t &port)
        : port_(port)
    {
        Content_Type.insert({".html","text/html"});
        Content_Type.insert({".jpg","image/jpeg"});
    }
   static std::string ReadHtmlFile(const std::string&path)//这里可能读到的是二进制文件
    {
        //打开文件，读文件
        std::ifstream in(path,std::ios::binary);
        if(!in.is_open())return "";
        in.seekg(0,std::ios_base::end);//定位到文件末尾
        auto len=in.tellg();//获取文件大小
        in.seekg(0,std::ios_base::beg);//定位回文件开头
        std::string content;
        content.resize(len);//开好len空间大小
        in.read((char*)content.c_str(),content.size());
        // std::string line;
        // std::string res;
        // while(getline(in,line))
        // {
        //     res+=line;
        // }
        in.close();//关闭文件
         return content;
    }
   std::string SuffixToDescc(const std::string&suffix)
    {
        auto iter=Content_Type.find(suffix);
        if(iter==Content_Type.end())return Content_Type[".html"];
        else
        return Content_Type[suffix];
    }
   void HandlerHtml(int fd)
    {

        char buffer[10240];
        size_t n = recv(fd, buffer, sizeof(buffer) - 1, 0);
        if (n > 0)
        {
            // 读取成功
            buffer[n] = 0;
            
            // std::cout<<buffer<<std::endl;
            Request rq;
            rq.Deserialize(buffer);//反序列化
            rq.Parsing();//解析
            rq.DebugPrint();
            std::string response_text = ReadHtmlFile(rq.file_path);     // 响应正文
          
          bool ok=true;
            if(response_text.empty())
            {
                ok=false;
                //如果没有这个文件就返回出错页面
               std::string err_html=wwwroot;
               err_html+="/";
               err_html+="error.html";
               response_text=ReadHtmlFile(err_html);
            }
            std::string response_line;
            if(ok==true)
            {
           response_line = "HTTP/1.1 200 success"; // 响应状态行
            }
            else
            {
                response_line="HTTP/1.1 404 error";
            }
            std::string response_headler = "Content-Length:";//正文长度属性
            response_headler += std::to_string(response_text.size()); // 响应报头
            response_headler+=protocol_sep;
            response_headler+="Content-Type:";//数据类型属性
            response_headler+=SuffixToDescc(rq.suffix_);//通过后缀转对应的Content-Type;
            response_headler+=protocol_sep;
            response_headler+="Set-Cookie: name=haha&&passwd=12345";//Cookie属性，用来保持登陆状态

            std::string response = response_line;
            response += protocol_sep;
            response += response_headler;
            response += protocol_sep;
             response += protocol_sep;
            response += response_text;
            send(fd, response.c_str(), response.size(), 0);
        }
        close(fd); // 关闭soncket文件描述符对应文件
    }

    static void *ThreadRun(void *args)
    {
        pthread_detach(pthread_self());                   // 线程分离
        ThreadData *td = static_cast<ThreadData *>(args); // 强转
        td->ts->HandlerHtml(td->fd_);
        delete td;
        return nullptr;
    }
    void Start()
    {
        listen_fd.Socket();    // 创建套接字
        listen_fd.Bind(port_); // 绑定套接字
        listen_fd.Linsten();   // 让服务器处于等待被连接状态
        // 走到这里初始化工作完成
        lg(INFO, "Server init success!!");

        // 开始提供服务
        while (true)
        {
            uint16_t clientport;
            std::string clientip;
            int sockfd = listen_fd.Accept(&clientport, &clientip);
            if (sockfd < 0)
                continue; // 如果获取新连接失败继续获取
            lg(INFO, "Server get a new link,sockfd is: %d", sockfd);
            // 走到这里获取到新链接
            // 让子线程提供服务，父线程继续获取新链接
            ThreadData *td = new ThreadData();
            td->fd_ = sockfd;
            td->ts=this;
            pthread_t id;
            pthread_create(&id, nullptr, ThreadRun, td);
        }
    }
    ~TcpServer()
    {
    }
    
private:
    uint16_t port_;
    Sock listen_fd;
    std::unordered_map<std::string,std::string> Content_Type;
};